import type { Company, Department, DownloadFormat, DragElement, DragTableElementColumn, Menu } from "@/typings";

const map = new WeakMap();

/**
 * @description 获取浏览器默认语言
 * @returns {String}
 */
export function getBrowserLanguage(): string {
  const browserLang = window.navigator.language;
  let defaultBrowserLang = "";
  if (["cn", "zh", "zh-cn"].includes(browserLang.toLowerCase())) {
    defaultBrowserLang = "zh";
  } else {
    defaultBrowserLang = "en";
  }
  return defaultBrowserLang;
}

/**
 * @description 使用递归找出所有面包屑存储到 pinia/vuex 中
 * @param {Menu[]} menuList 菜单列表
 * @param {Array} parent 父级菜单
 * @param {Object} result 处理后的结果
 * @returns {Object}
 */
export const getAllBreadcrumbList = (menuList: Menu[], parent = [], result: { [key: string]: any } = {}) => {
  for (const item of menuList) {
    result[item.path] = [...parent, item];
    if (item.children) getAllBreadcrumbList(item.children, result[item.path], result);
  }
  return result;
};

/**
 * @description 使用递归扁平化菜单，方便加动态路由
 * @param {Array} menuList 菜单列表添
 * @returns {Array}
 */
export function getFlatMenuList(menuList: Menu[]): Menu[] {
  const newMenuList: Menu[] = JSON.parse(JSON.stringify(menuList));
  return newMenuList.flatMap((item) => [item, ...(item.children ? getFlatMenuList(item.children) : [])]);
}

/**
 * @description 获取当前时间对应的提示语
 * @returns {String}
 */
export function getTimeState(): string {
  const timeNow = new Date();
  const hours = timeNow.getHours();
  if (hours >= 6 && hours <= 10) return `早上好呀！ ⛅`;
  if (hours >= 10 && hours <= 14) return `中午好呀！ 🌞`;
  if (hours >= 14 && hours <= 18) return `下午好呀！ 🌞`;
  if (hours >= 18 && hours <= 24) return `晚上好呀！ 🌛`;
  if (hours >= 0 && hours <= 6) return `凌晨好呀！ 🌛`;
  return "你好呀！";
}

/**
 * @description 是否为undefined或者null
 * @param value
 * @returns
 */
export function isUndefinedOrNull(value: any): boolean {
  return isUndefined(value) || value === null;
}

/**
 * @description 部门树形结构装换
 * @param list 部门列表
 * @param deptId 父级部门id
 */
export const deptDeepTree = (list: Department[], deptCode: string = ""): Department[] => {
  const result: Department[] = [];
  if (list.length <= 1) return list;
  list.forEach((item) => {
    if (item.parentCode === deptCode) {
      item.children = deptDeepTree(list, item.deptCode);
      result.push(item);
    }
  });
  return result;
};

/**
 * @description 组织树形结构转换
 * @param list 组织列表
 * @param deptId 父级组织id
 */
export const companyDeepTree = (list: Company[], pid: string = ""): Company[] => {
  const result: Company[] = [];
  if (list.length <= 1) return list;
  list.forEach((item) => {
    if (item.partentId === pid) {
      item.children = companyDeepTree(list, item.companyId);
      result.push(item);
    }
  });
  return result;
};

/**
 * @description 获取随机数
 * @param {number} start 开始位置
 * @param {number} end 结束位置
 * @param {number} decimal 小数位数 默认0
 * @returns {number}
 */
export const random = (start: number, end: number, decimal: number = 0): number => {
  if (start >= end) return end;
  const range = end - start;
  const rendomDecimal = Math.random() * range;
  const result = Number(rendomDecimal.toFixed(decimal));
  return Math.min(start, end) + result;
};

/**
 * @description 图片转base64格式
 * @param url 图片地址
 * @param format base64转换图片格式
 * @returns {Promise<string>}
 */
export const imageUrlToBase64 = async (url: string, format: string = "jpeg"): Promise<string> => {
  const image = new Image();
  image.setAttribute("crossOrigin", "anonymous");
  image.src = url;
  return await new Promise((resolve, redirect) => {
    try {
      image.onload = () => {
        const canvas = document.createElement("canvas");
        canvas.width = image.width;
        canvas.height = image.height;
        const context = canvas.getContext("2d");
        context?.drawImage(image, 0, 0, image.width, image.height);
        const quality = 0.8;
        resolve(canvas.toDataURL("image/" + format, quality));
      };
    } catch (error) {
      redirect("base64格式转换失败");
    }
  });
};

/**
 * @description 文件转base64
 * @param file 转换的文件
 * @returns
 */
export const fileToBase64 = async (file: File): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function () {
      resolve(reader.result as string);
    };
    reader.onerror = function () {
      reject(new Error("文件转base64失败"));
    };
  });
};

/**
 * @description 合成拖拽数据
 * @param {DragTableElementColumn} columns 表格列
 * @param {DragElement} oldDragList 原始拖拽的元素列表
 * @requires DragElement 新的拖拽列表数据
 */
export const compoundProvider = (columns: DragTableElementColumn[], oldDragList: DragElement[]): DragElement[] => {
  if (columns.length <= 0) return oldDragList;
  const findItem = oldDragList.find((item: DragElement) => item.type === "table");
  if (findItem) {
    findItem.columns = [columns];
  }
  return oldDragList;
};

/**
 * @description 下载
 * @param data 数据
 * @param filename 文件名称
 * @param postfix 格式
 */
export const downloadHandler = (data: string, filename: string = "download", postfix: DownloadFormat = "text"): void => {
  const downloadFile = "data:text/json;charset=utf-8," + encodeURIComponent(data);
  const link = document.createElement("a");
  link.href = downloadFile;
  link.download = `${filename}.${postfix}`;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
};

export const createChildren = (list: any[], pid: any) => {
  const tree: any[] = [];
  list.forEach((item: any) => {
    if (item.pid === pid) {
      item.children = createChildren(list, item.id);
      tree.push(item);
    }
  });
  return tree;
};

/**
 * @description 控制表单显示
 * @param current 当前选中的项
 * @param list 可显示的所有项
 */
export const statusShow = (current: number | string, list: number[]): boolean => {
  for (let i = 0; i < list.length; i++) {
    const item = list[i];
    if (item == current) {
      return true;
    }
  }
  return false;
};

/**
 * 判断对象是否存在
 * @param obj
 * @returns
 */
export const isExist = (obj: any): boolean => {
  return obj !== undefined && obj !== null;
};

/**
 * 是否未定义
 * @param value
 * @returns
 */
export const isUndefined = (value: any): boolean => {
  return typeof value === "undefined";
};

/**
 * 是否为空
 * @param val
 * @returns
 */
export const isEmpty = (val: any): boolean => {
  return isUndefined(val) || Object.is(val, "") || val === null || val !== val;
};

/**
 * 判断是否为一个函数
 * @param func
 * @returns
 */
export const isFunction = (func: any): boolean => {
  return typeof func === "function";
};

/**
 * 是否是数字值(包括可转换的,已排除了空值)
 * @param num
 * @returns
 */
export const isNumber = (num: any): boolean => {
  return !isEmpty(num) && !isNaN(num);
};

/**
 * 深拷贝
 * @param obj
 * @returns
 */
export const deepCopy = <T>(obj: T): T => {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  if (obj instanceof Date) {
    return new Date(obj.getTime()) as any;
  }
  if (obj instanceof Array) {
    const newArr = [];
    for (let i = 0; i < obj.length; i++) {
      newArr[i] = deepCopy(obj[i]);
    }
    return newArr as any;
  }
  if (obj instanceof Object) {
    const newObj: any = {};
    for (const key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        newObj[key] = deepCopy(obj[key]);
      }
    }
    return newObj as any;
  }
  return obj;
};

/**
 * 是否为空对象（包括值）
 * @param source
 */
export const isEmptyObject = (source: any): boolean => {
  if (isEmpty(source)) return true;
  if (source.toString() === "[object Object]") {
    let flag: boolean = true;
    for (const key of Object.keys(source)) {
      if (!isEmptyObject(source[key])) {
        flag = false;
      }
    }
    return flag;
  } else {
    return false;
  }
};

/**
 * 节流
 *
 * @param {any} fun 函数
 * @param {any} params 参数
 * @param {any} context 方法上下文
 * @param {number} delay 延迟时间，默认300
 * @static
 */
export const throttle: Function = (fun: any, params: any[], context: any, delay: number = 300) => {
  const now: any = Date.now();
  if (!fun.last || now - fun.last >= delay) {
    if (typeof fun === "function") {
      return fun.apply(context, params);
    }
    fun.last = now;
  }
};

/**
 * 防抖
 *
 * @param {any} fun 函数
 * @param {any} params 参数
 * @param {number} wait 延迟时间，默认300
 * @static
 */
export const debounce: Function = (fun: any, params: any, wait: number = 300) => {
  if (typeof fun === "function") {
    if (map.has(fun)) {
      const num = map.get(fun);
      clearTimeout(num);
    }
    map.set(
      fun,
      setTimeout(() => {
        map.delete(fun);
        fun(params);
      }, wait)
    );
  }
};
